/*
 * ConnectThread.java
 *
 * Created on May 28, 2008, 2:36 PM
 *
 */

package orajdbcstat;

import java.io.*;
import java.net.*;
import java.util.*;
import java.sql.*;
import java.math.*;
import oracle.jdbc.driver.*;
import oracle.jdbc.pool.*;
import oracle.jdbc.rowset.*;

/**
 *
 * @author vnull
 */
public class ConnectThread implements Runnable {
    Long newConnTCPTime = new Long(0);
    Long newConnJDBCTime = new Long(0);
    Integer newConnActiveInstance = new Integer(-1);
    Integer newConnActiveInstanceOld = new Integer(-1);
    String newConnInstanceIP = null;
    
    Boolean ok = true;
    Boolean tcpcheck = true;
    Instance instance = null;
    Configuration conf = null;
    
    /** Creates a new instance of ConnectThread */
    public ConnectThread(Instance instance, Configuration conf) {
        this.instance = instance;
        this.conf = conf;
    }
    
    public Long getTCPTime() {
        return newConnTCPTime;
    }
    
    public Long getJDBCTime() {
        return newConnJDBCTime;
    }
    
    public Integer getNewConnActiveInstance() {
        return newConnActiveInstance;
    }
    
    public Integer getNewConnActiveInstanceOld() {
        return newConnActiveInstanceOld;
    }
    
    public void DDLStatement(Connection db, String text) throws SQLException {
        if(db != null) {
            Statement s = db.createStatement();
            s.executeUpdate(text);
            db.commit();
            s.close();
        }
    }
    
    
    public void run() {
        while(ok) {
            Long timerStart = System.currentTimeMillis();
            
            try {
                /* Direct connection without OracleDataSource as we don't want to check pooling, FCF and so on */
                DriverManager.setLoginTimeout(conf.networkDelay_driverManager);
                Connection tempConn = DriverManager.getConnection("jdbc:oracle:oci:@"+instance.TNS, conf.login, conf.pass);
                tempConn.setAutoCommit(false);
                
                Statement s = tempConn.createStatement();
                // TODO:
                //s.setQueryTimeout(newConnActiveInstance)
                ResultSet r = s.executeQuery("SELECT SYS_CONTEXT('USERENV', 'INSTANCE') FROM DUAL");
                r.next();
                newConnActiveInstanceOld = newConnActiveInstance;
                newConnActiveInstance = r.getInt(1);
                
                newConnJDBCTime = System.currentTimeMillis() - timerStart;
                
                /* pick first available public IP address, hopefully we can connect there */
                if(tcpcheck == true) {
                    Statement s2;
                    ResultSet ip;
                    try {
                        s2 = tempConn.createStatement();
                        // TODO
                        // s2.setQueryTimeout(newConnActiveInstance);
                        ip = s2.executeQuery("SELECT IP_KSXPIA FROM (SELECT IP_KSXPIA FROM X$KSXPIA WHERE PUB_KSXPIA='Y' AND IP_KSXPIA IS NOT NULL AND IP_KSXPIA != '0.0.0.0') WHERE ROWNUM = 1");
                        
                        if(ip.next()) {
                            newConnInstanceIP = ip.getString(1);
                            try {
                                timerStart = System.currentTimeMillis();
                                Socket sock = new Socket(newConnInstanceIP, conf.listenerPort);
                                sock.close();
                                newConnTCPTime = System.currentTimeMillis() - timerStart;
                            } catch (Exception e) {
                                if(conf.verbose >= 2) {
                                    System.err.println("TCP Connect(" + instance.TNS + ", " + conf.listenerPort + "): " + e.toString());
                                }
                                newConnInstanceIP = null;
                                newConnTCPTime = new Long(0);
                            }
                        } else {
                            newConnInstanceIP = null;
                            newConnTCPTime = new Long(0);
                        }
                        ip.close();
                        s2.close();
                    }  catch(SQLException e) {
                        System.err.println("TCP Connect(" + instance.TNS + ", " + conf.listenerPort + "): " + e.getMessage());

                        /* Table does not exists */
                        if(e.getErrorCode() == 942)  {
                            tcpcheck = false;
                            System.err.println("TCP Connect(" + instance.TNS + ", " + conf.listenerPort + "): " + "disabling TCP probe");
                        }
                    }
                } else {
                    newConnInstanceIP = null;
                    newConnTCPTime = new Long(0);
                }
                
                r.close();
                s.close();
                tempConn.close();
            } catch (SQLException e) {
                if(newConnActiveInstance == -1) {
                    newConnActiveInstanceOld = -1;
                } else {
                    newConnActiveInstance = -1;
                }
                
                newConnJDBCTime = new Long(-e.getErrorCode());
                newConnTCPTime = new Long(-e.getErrorCode());
                
                //System.err.println("NEWCONN/THREAD["+instance.TNS+"] " + e.getMessage());
            }
            
            try {
                Long timeToSleep = Math.max((conf.delay*1000) - (System.currentTimeMillis() - timerStart), 0);
                Thread.sleep(timeToSleep);
            } catch(InterruptedException e) {
                
            }
        }
        
    }
    
}
